package com.doeis.minaserver.module;

import java.util.HashMap;
import java.util.Map;

import com.doeis.common.utils.StringUtils;
import com.doeis.minaserver.NettyServer;
import com.doeis.minaserver.container.BasicModule;
import com.doeis.minaserver.nio.NioServiceEventLoop;
import com.doeis.minaserver.nio.NioServiceEventLoopGroup;
import com.doeis.minaserver.packet.InfoPacket;
import com.doeis.minaserver.packet.ServerPacketFactory;
import com.doeis.minaserver.session.ClientConnection;

/**
 *	客户端连接控制
 *  @author tianbx 
 * ***/
public class ClientConnectionManager extends BasicModule {
	
	private NioServiceEventLoopGroup nioServiceEventLoopGroup = null;
	
	/**
	 * 验证与非验证的连接
	 */
	private HashMap<String, ClientConnection> connections;
	private HashMap<String, ClientConnection> authConnections;
	
	
	

	public ClientConnectionManager() {
		super("Client Connection Manager");
	}

	@Override
	public void initialize(NettyServer server) {
		super.server = server;		
	}

	@Override
	public void start() {
		nioServiceEventLoopGroup = new  NioServiceEventLoopGroup();
		connections =  new HashMap<String, ClientConnection>() ;
		authConnections = new HashMap<String, ClientConnection>() ;
	}

	@Override
	public void stop() {
		connections = null;
		authConnections = null;
		if(nioServiceEventLoopGroup!=null){
			nioServiceEventLoopGroup.shutdownGracefully();
			nioServiceEventLoopGroup = null;
		}
	}
	
	/**
	 * 取得已经通过验证的用户链接
	 * @return
	 */
	public Map<String, ClientConnection> getAuthConnections(){
		return authConnections;
	}
	
	public Map<String, ClientConnection> getConnections(){
		return connections;
	}
	
	/**
	 * 取得已经登陆过的客户网络连接通道
	 * @param userid
	 * @return
	 */
	public ClientConnection getAuthConnection(String userid){
		return authConnections.get(userid);
	}
	
	/**
	 * @return
	 */
	public ClientConnection getConnection(long l){
		return connections.get(String.valueOf(l));
	}
	
	private void addAuthConnection(ClientConnection conn){
		String uid = conn.getUserid();
		authConnections.put(uid, conn);
	}
	
	/**
	 * 如果网络连接关闭了，就从io连接缓存池中删除连接。
	 * 如果连接已经经过验证，就从验证中删除，否则从非验证的连接中删除
	 * @param conn
	 */
	public void removeConnectionAfterClose(ClientConnection conn){
		// 从缓存池中删除
		String userid = conn.getUserid();
		if( !StringUtils.isBlank(userid) ){
			// 这里移除一定要传入两个参数，因为这个方法会在io连接关闭时调用
			// 如果不两个值一起来确定删除，在踢人的时候就有可能把自己的也删除了
			if(authConnections!=null){
				ClientConnection temp =	authConnections.get(userid);
				if(temp!=null && temp.equals(conn)){
					authConnections.remove(userid);
				}
//				authConnections.remove(userid);//这个方法是错误的，老师把自己删除
			}
		}else{
			removeConnection(conn);
		}
	}
	
	public int countAuthConnection(){
		return authConnections.size();
	}
	
	public int countUnauthConnection(){
		return connections.size();
	}
	
	public void addConnection(ClientConnection conn){
		String l = conn.getChannelHandlerContext().channel().id().asLongText();
		connections.put(l, conn);		
	}
	
	private void removeConnection(ClientConnection conn){
		String l = conn.getChannelHandlerContext().channel().id().asLongText();
		if(connections!=null){
//			connections.remove(l,conn);
			connections.remove(l);
		}
	}
	
	/**
	 * 加一把锁，防止多个线程同时调用
	 * **/
	public synchronized void  changeConnectionToAuth(ClientConnection newconn){	
		//首先处理是否
		ClientConnection otherConn = getAuthConnection(newconn.getUserid());
		if (otherConn!=null) {
			if(otherConn.getChannelHandlerContext().channel().id().asLongText().equals(
					newconn.getChannelHandlerContext().channel().id().asLongText())){
				//同一个连接进行了多次登陆，什么都不进行操作
			}else{
				//这里处理特殊的情况，一个手机进行了多次登陆，系统自动的把前面的连接关闭掉
				if(newconn.getRegistrationID()!=null && otherConn.getRegistrationID()!=null){
					if(newconn.getRegistrationID().equals(otherConn.getRegistrationID())){
						otherConn.close();
					}else{
						InfoPacket info = ServerPacketFactory.createInfoPacket( newconn.getUserid() );
						info.setCmd(InfoPacket.NOTIFY_USER_LOGIN_OUT);
						info.setNotifyType(InfoPacket.NT_USER_FORCE_QUIT);
						otherConn.deliver(info);
					}
				}else{
					InfoPacket info = ServerPacketFactory.createInfoPacket( newconn.getUserid() );
					info.setCmd(InfoPacket.NOTIFY_USER_LOGIN_OUT);
					info.setNotifyType(InfoPacket.NT_USER_FORCE_QUIT);
					otherConn.deliver(info);
				}
			}
		}
		addAuthConnection(newconn);
		removeConnection(newconn);
	}
	
	public NioServiceEventLoop next(){
		return nioServiceEventLoopGroup.next();
	}

	
	
	
}
